use std::sync::Arc;
use core::{Source, Package, Target};
-use core::{Profile, TargetKind, Profiles, Workspace, PackageIdSpec};
+use core::{Profile, TargetKind, Profiles, Workspace, PackageId, PackageIdSpec};
+use core::resolver::Resolve;
use ops::{self, BuildOutput, Executor, DefaultExecutor};
use util::config::Config;
use util::{CargoResult, profile};
}
} else {
let root_package = ws.current()?;
- let all_features = resolve_with_overrides.features(root_package.package_id());
- generate_targets(root_package, profiles, mode, filter, all_features, release)?;
+ let all_features = resolve_all_features(&resolve_with_overrides, root_package.package_id());
+ generate_targets(root_package, profiles, mode, filter, &all_features, release)?;
pkgids.push(root_package.package_id());
};
panic!("`rustc` and `rustdoc` should not accept multiple `-p` flags")
}
(Some(args), _) => {
- let all_features = resolve_with_overrides.features(to_builds[0].package_id());
+ let all_features = resolve_all_features(&resolve_with_overrides, to_builds[0].package_id());
let targets = generate_targets(to_builds[0], profiles,
- mode, filter, all_features, release)?;
+ mode, filter, &all_features, release)?;
if targets.len() == 1 {
let (target, profile) = targets[0];
let mut profile = profile.clone();
}
}
(None, Some(args)) => {
- let all_features = resolve_with_overrides.features(to_builds[0].package_id());
+ let all_features = resolve_all_features(&resolve_with_overrides, to_builds[0].package_id());
let targets = generate_targets(to_builds[0], profiles,
- mode, filter, all_features, release)?;
+ mode, filter, &all_features, release)?;
if targets.len() == 1 {
let (target, profile) = targets[0];
let mut profile = profile.clone();
}
(None, None) => {
for &to_build in to_builds.iter() {
- let all_features = resolve_with_overrides.features(to_build.package_id());
+ let all_features = resolve_all_features(&resolve_with_overrides, to_build.package_id());
let targets = generate_targets(to_build, profiles, mode,
- filter, all_features, release)?;
+ filter, &all_features, release)?;
package_targets.push((to_build, targets));
}
}
ret.to_doc_test = to_builds.iter().map(|&p| p.clone()).collect();
- Ok(ret)
+ return Ok(ret);
+
+ fn resolve_all_features(resolve_with_overrides: &Resolve,
+ package_id: &PackageId)
+ -> HashSet<String> {
+ let mut features = match resolve_with_overrides.features(package_id) {
+ Some(all_features) => all_features.clone(),
+ None => HashSet::new(),
+ };
+
+ // Include features enabled for use by dependencies so targets can also use them with the
+ // required-features field when deciding whether to be built or skipped.
+ let deps = resolve_with_overrides.deps(package_id);
+ for dep in deps {
+ if let Some(dep_features) = resolve_with_overrides.features(dep) {
+ for feature in dep_features {
+ features.insert(dep.name().to_string() + "/" + feature);
+ }
+ }
+ }
+
+ features
+ }
}
impl<'a> CompileFilter<'a> {
profiles: &'a Profiles,
mode: CompileMode,
filter: &CompileFilter,
- features: Option<&HashSet<String>>,
+ features: &HashSet<String>,
release: bool)
-> CargoResult<Vec<(&'a Target, &'a Profile)>> {
let build = if release {&profiles.release} else {&profiles.dev};
};
//Collect the targets that are libraries or have all required features available.
- let no_features = HashSet::new();
- let features = features.unwrap_or(&no_features);
let mut compatible_targets = Vec::with_capacity(targets.len());
for (target, profile) in targets.drain(0..) {
if target.is_lib() || match target.required_features() {
assert_that(cargo_home(), not(has_installed_exe("foo_1")));
assert_that(cargo_home(), not(has_installed_exe("foo_2")));
}
+
+#[test]
+fn dep_feature_in_toml() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies]
+ bar = { path = "bar", features = ["a"] }
+
+ [[bin]]
+ name = "foo"
+ required-features = ["bar/a"]
+
+ [[example]]
+ name = "foo"
+ required-features = ["bar/a"]
+
+ [[test]]
+ name = "foo"
+ required-features = ["bar/a"]
+
+ [[bench]]
+ name = "foo"
+ required-features = ["bar/a"]
+ "#)
+ .file("src/main.rs", "fn main() {}")
+ .file("examples/foo.rs", "fn main() {}")
+ .file("tests/foo.rs", "#[test]\nfn test() {}")
+ .file("benches/foo.rs", r#"
+ #![feature(test)]
+ extern crate test;
+
+ #[bench]
+ fn bench(_: &mut test::Bencher) {
+ }"#)
+ .file("bar/Cargo.toml", r#"
+ [project]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+ "#)
+ .file("bar/src/lib.rs", "");
+ p.build();
+
+ assert_that(p.cargo("build"),
+ execs().with_status(0));
+
+ // bin
+ assert_that(p.cargo("build").arg("--bin=foo"),
+ execs().with_status(0));
+ assert_that(&p.bin("foo"), existing_file());
+
+ // example
+ assert_that(p.cargo("build").arg("--example=foo"),
+ execs().with_status(0));
+ assert_that(&p.bin("examples/foo"), existing_file());
+
+ // test
+ assert_that(p.cargo("test").arg("--test=foo"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+"));
+
+ // bench
+ if is_nightly() {
+ assert_that(p.cargo("bench").arg("--bench=foo"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] bar v0.0.1 ({0}/bar)
+[COMPILING] foo v0.0.1 ({0})
+[FINISHED] release [optimized] target(s) in [..]
+[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test bench ... bench: [..] 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+
+"));
+ }
+
+ // install
+ assert_that(p.cargo("install"),
+ execs().with_status(0));
+ assert_that(cargo_home(), has_installed_exe("foo"));
+ assert_that(p.cargo("uninstall").arg("foo"),
+ execs().with_status(0));
+}
+
+#[test]
+fn dep_feature_in_cmd_line() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [project]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies]
+ bar = { path = "bar" }
+
+ [[bin]]
+ name = "foo"
+ required-features = ["bar/a"]
+
+ [[example]]
+ name = "foo"
+ required-features = ["bar/a"]
+
+ [[test]]
+ name = "foo"
+ required-features = ["bar/a"]
+
+ [[bench]]
+ name = "foo"
+ required-features = ["bar/a"]
+ "#)
+ .file("src/main.rs", "fn main() {}")
+ .file("examples/foo.rs", "fn main() {}")
+ .file("tests/foo.rs", "#[test]\nfn test() {}")
+ .file("benches/foo.rs", r#"
+ #![feature(test)]
+ extern crate test;
+
+ #[bench]
+ fn bench(_: &mut test::Bencher) {
+ }"#)
+ .file("bar/Cargo.toml", r#"
+ [project]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ a = []
+ "#)
+ .file("bar/src/lib.rs", "");
+ p.build();
+
+ assert_that(p.cargo("build"),
+ execs().with_status(0));
+
+ // bin
+ assert_that(p.cargo("build").arg("--bin=foo"),
+ execs().with_status(101).with_stderr("\
+error: target `foo` requires the features: `bar/a`
+Consider enabling them by passing e.g. `--features=\"bar/a\"`
+"));
+
+ assert_that(p.cargo("build").arg("--bin=foo").arg("--features").arg("bar/a"),
+ execs().with_status(0));
+ assert_that(&p.bin("foo"), existing_file());
+
+ // example
+ assert_that(p.cargo("build").arg("--example=foo"),
+ execs().with_status(101).with_stderr("\
+error: target `foo` requires the features: `bar/a`
+Consider enabling them by passing e.g. `--features=\"bar/a\"`
+"));
+
+ assert_that(p.cargo("build").arg("--example=foo").arg("--features").arg("bar/a"),
+ execs().with_status(0));
+ assert_that(&p.bin("examples/foo"), existing_file());
+
+ // test
+ assert_that(p.cargo("test"),
+ execs().with_status(0).with_stderr(format!("\
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]"))
+ .with_stdout(""));
+
+ assert_that(p.cargo("test").arg("--test=foo").arg("--features").arg("bar/a"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] foo v0.0.1 ({})
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+
+"));
+
+ // bench
+ if is_nightly() {
+ assert_that(p.cargo("bench"),
+ execs().with_status(0).with_stderr(format!("\
+[FINISHED] release [optimized] target(s) in [..]"))
+ .with_stdout(""));
+
+ assert_that(p.cargo("bench").arg("--bench=foo").arg("--features").arg("bar/a"),
+ execs().with_status(0).with_stderr(format!("\
+[COMPILING] bar v0.0.1 ({0}/bar)
+[COMPILING] foo v0.0.1 ({0})
+[FINISHED] release [optimized] target(s) in [..]
+[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
+ .with_stdout("
+running 1 test
+test bench ... bench: [..] 0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+
+"));
+ }
+
+ // install
+ assert_that(p.cargo("install"),
+ execs().with_status(101).with_stderr(format!("\
+[INSTALLING] foo v0.0.1 ([..])
+[FINISHED] release [optimized] target(s) in [..]
+[ERROR] no binaries are available for install using the selected features
+")));
+ assert_that(cargo_home(), not(has_installed_exe("foo")));
+
+ assert_that(p.cargo("install").arg("--features").arg("bar/a"),
+ execs().with_status(0));
+ assert_that(cargo_home(), has_installed_exe("foo"));
+ assert_that(p.cargo("uninstall").arg("foo"),
+ execs().with_status(0));
+}